package club.ruanx.movie.service.impl;


import club.ruanx.bean.PageBean;
import club.ruanx.core.exception.TargetEntityNotFound;
import club.ruanx.core.service.base.BaseServiceImpl;
import club.ruanx.movie.common.aop.annotation.DeleteOnSolr;
import club.ruanx.movie.common.aop.annotation.SaveOnSolr;
import club.ruanx.movie.common.constraint.MovieRedisConstraint;
import club.ruanx.movie.entity.Movie;
import club.ruanx.movie.param.MovieParam;
import club.ruanx.movie.repository.MovieRepository;
import club.ruanx.movie.service.MovieService;
import club.ruanx.util.BeanUtils;
import club.ruanx.util.CollectionUtils;
import club.ruanx.util.StringUtils;
import com.alibaba.fastjson.JSON;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Set;

/**
 * @author 阮胜
 * @date 2018/10/21 20:16
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class MovieServiceImpl extends BaseServiceImpl<Movie, String, MovieRepository> implements MovieService {
    private static final String COMMA = ",";
    public static final String EH_CACHE_MOVIE_QUERY = "EhCache:Movie:Query";
    private final RedisTemplate<String, Object> redisTemplate;

    public MovieServiceImpl(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    @SaveOnSolr
    public Movie save(Movie movie) {
        return super.save(movie);
    }

    @Override
    @SaveOnSolr
    public Movie save(MovieParam movieParam) {
        Movie movie = new Movie();
        if (!StringUtils.isEmpty(movieParam.getTypes())) {
            movie.setTypes(JSON.toJSONString(movieParam.getTypes()));
        }

        if (!StringUtils.isEmpty(movieParam.getLanguages())) {
            movie.setLanguages(JSON.toJSONString(movieParam.getLanguages()));
        }
        if (!StringUtils.isEmpty(movieParam.getAreas())) {
            movie.setAreas(JSON.toJSONString(movieParam.getAreas()));
        }
        BeanUtils.copyPropertiesIgnoreNull(movieParam, movie);
        return repository.save(movie);
    }

    @Override
    public int findMovieHot(String movieId) {
        ZSetOperations<String, Object> ops = redisTemplate.opsForZSet();
        Double movieHot = ops.score(MovieRedisConstraint.MOVIE_HOT_ZSET, movieId);
        return movieHot == null ? 0 : movieHot.intValue();
    }

    @Override
    public int increaseMovieHot(String movieId, int increment) {
        ZSetOperations<String, Object> ops = redisTemplate.opsForZSet();
        Double currentMovieHot = ops.incrementScore(MovieRedisConstraint.MOVIE_HOT_ZSET, movieId, increment);
        return currentMovieHot == null ? 0 : currentMovieHot.intValue();
    }

    @Override
    public Page<Movie> findByCreateTime(PageBean pageBean) {
        return repository.findAllByOrderByCreateTimeDesc(pageBean.toPageable());
    }

    @Override
    public List<Movie> findHotList(int count) {
        Set<ZSetOperations.TypedTuple<Object>> zSet = redisTemplate.opsForZSet()
                .reverseRangeWithScores(MovieRedisConstraint.MOVIE_HOT_ZSET, 0, count);
        if (CollectionUtils.isEmpty(zSet)) {
            return null;
        }
        String[] ids = zSet.stream()
                .map(objectTypedTuple -> String.valueOf(objectTypedTuple.getValue()))
                .toArray(value -> new String[zSet.size()]);
        return repository.findByIdIn(ids);
    }

    @Override
    public Page<Movie> findByRate(PageBean pageBean) {
        return repository.findAllByOrderByRateDesc(pageBean.toPageable());
    }

    @Override
    public Page<Movie> findByType(Integer type, PageBean pageBean) {
        return repository.findAllByType(type, pageBean.toPageable());
    }

    @Override
    public boolean existsBySpiderId(String spiderId) {
        return repository.existsBySpiderId(spiderId);
    }

    @Override
    public Page<Movie> findByActorOrDirector(String actor, String director, PageBean pageBean) {
        return repository.findAllByActorsContainingOrDirectorsContaining(actor, director, pageBean.toPageable());
    }

    @Override
    public Page<Movie> findAllOrderByCreateTimeDesc(PageBean pageBean) {
        return repository.findAllByOrderByCreateTimeDesc(pageBean.toPageable());
    }

    @Cacheable(value = EH_CACHE_MOVIE_QUERY, key = "'findById'+#id")
    @Override
    public Movie findById(String id) throws TargetEntityNotFound {
        return super.findById(id);
    }

    @CacheEvict(value = EH_CACHE_MOVIE_QUERY, key = "#movieId")
    @DeleteOnSolr(key = "#movieId")
    @Override
    public void delete(String movieId) throws Exception {
        super.delete(movieId);
    }
}
